part of 'index.dart';

enum CustomMessageType {
  gift('gift'),
  share('share'),
  call('call'),
  callUP('callUP'),
  receiveUP('receiveUP'),
  invisible('invisible');

  const CustomMessageType(this.value);
  final String value;
}

class ImManager {
  ImManager._();
  static final ImManager of = ImManager._();
  bool isInitialized = false;
  bool logined = false;
  static const customerId = '2000000_00000000';
  static const systemNoticeId = 'proclamation_admin';
  static const platformNoticeId = 'notice_admin';
  static const likeId = 'dynamic_like_admin';
  static const commentId = 'dynamic_comment_admin';
  static const giftId = 'dynamic_reward_admin';

  //proclamation_admin
  Set<String> onlineUsers = {};

  final _messageStreamController =
      StreamController<List<EMMessage>>.broadcast();
  Stream<List<EMMessage>> get messageStream => _messageStreamController.stream;

  final _conversationStreamController = StreamController<void>.broadcast();
  Stream<void> get conversationStream => _conversationStreamController.stream;

  Future<void> init() async {
    if (isInitialized) return;
    await _initSDK();
    _addChatListener();
    debugPrint("==IM==:IMSDK初始化成功");
  }
  // ============================== sdk =========================================

  Future<void> _initSDK() async {
    final options = chat.Options.withAppKey(
      '1155241212169678#yahabbi',
      autoLogin: true,
      enableEmptyConversation: false,
    );
    await EMClient.getInstance.init(options);
    await EMClient.getInstance.startCallback();
    isInitialized = true;
    logined = await isLogin();
  }

  // ============================== user =========================================

  Future<bool> signIn({
    required String username,
    required String password,
  }) async {
    if (!isInitialized) return false;
    final uid = await currentUserId();
    if (uid == username) {
      logined = true;
      debugPrint("==IM==:$username IM登录成功(already)");
      return true;
    } else {
      await signOut();
    }
    try {
      await EMClient.getInstance.loginWithPassword(username, password);
      debugPrint("==IM==:$username IM登录成功");
      logined = true;
      //_sendToCustomer();
      return true;
    } on EMError catch (e) {
      debugPrint("==IM==:IM登录失败($username), e: ${e.code} , ${e.description}");
      return false;
    }
  }

  Future<bool> signOut() async {
    try {
      await EMClient.getInstance.logout(true);
      return true;
    } on EMError catch (e) {
      debugPrint("==IM==:IM登出失败, code: ${e.code}, desc: ${e.description}");
      return false;
    }
  }

  Future<bool> isLogin() async {
    try {
      return EMClient.getInstance.isLoginBefore();
    } on EMError catch (e) {
      debugPrint("I==IM==:M获取登录状态失败, code: ${e.code}, desc: ${e.description}");
      return false;
    }
  }

  Future<String?> currentUserId() async {
    try {
      return EMClient.getInstance.currentUserId;
    } on EMError catch (e) {
      debugPrint("==IM==:IM获取登录状态失败, code: ${e.code}, desc: ${e.description}");
      return null;
    }
  }

  // 更新用户信息
  Future<void> updateUserInfo({
    String? nickname,
    String? avatarUrl,
    String? mail,
    String? phone,
    int? gender,
    String? sign,
    String? birth,
    String? ext,
  }) async {
    if (!isInitialized) return;
    final status = await isLogin();
    if (!status) return;
    await EMClient.getInstance.userInfoManager.updateUserInfo(
      nickname: nickname,
      avatarUrl: avatarUrl,
      mail: mail,
      phone: phone,
      gender: gender,
      sign: sign,
      birth: birth,
      ext: ext,
    );
    return;
  }

  Future<chat.UserInfo?> fetchOwnInfo() async {
    final result = await EMClient.getInstance.userInfoManager.fetchOwnInfo();
    return result;
  }

  Future<chat.UserInfo?> fetchUserInfoById(String id) async {
    final result = await EMClient.getInstance.userInfoManager.fetchUserInfoById(
      [id],
    );
    final chat.UserInfo? user = result[id];
    return user;
  }

  Future<Map<String, chat.UserInfo>> fetchUserInfoByIds(
      List<String> ids) async {
    final result = await EMClient.getInstance.userInfoManager.fetchUserInfoById(
      ids,
    );
    return result;
  }

  Future<List<EMPresence>> fetchPresenceStatus(List<String> ids) async {
    List<EMPresence> list =
        await EMClient.getInstance.presenceManager.fetchPresenceStatus(
      members: ids,
    );
    return list;
  }

  Future<List<EMPresence>> fetchPresenceStatusById(String id) async {
    final list = await fetchPresenceStatus([id]);
    return list;
  }

  // ============================== message =========================================
  Future<EMMessage?> sendTextMessage({
    required String targetId,
    required String message,
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createTxtSendMessage(
      targetId: targetId,
      content: message,
    );
    try {
      EMMessage value = await EMClient.getInstance.chatManager.sendMessage(msg);
      return value;
    } catch (err) {
      debugPrint("==IM==:IM发送文本消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<chat.Message?> findMessage({
    required String msgId,
    VoidCallback? onError,
  }) async {
    try {
      return await EMClient.getInstance.chatManager.loadMessage(msgId);
    } catch (err) {
      debugPrint("==IM==:IM发送文本消息失败, err: $err");
      onError?.call();
    }
    return null;
  }

  Future<bool> downloadAttachmentByMsgId({
    required String msgId,
    VoidCallback? onError,
  }) async {
    try {
      final message = await findMessage(msgId: msgId);
      if (message == null) return false;
      await EMClient.getInstance.chatManager.downloadAttachment(message);
      return true;
    } catch (err) {
      debugPrint("==IM==:IM发送文本消息失败, err: $err");
      onError?.call();
      return false;
    }
  }

  Future<void> downloadAttachment({
    required chat.Message message,
    VoidCallback? onError,
  }) async {
    try {
      await EMClient.getInstance.chatManager.downloadAttachment(message);
    } catch (err) {
      debugPrint("==IM==:IM发送文本消息失败, err: $err");
      onError?.call();
    }
  }

  Future<EMMessage?> sendImageMessage({
    required String targetId,
    required String filePath,
    double? width,
    double? height,
    String? thumbnailLocalPath,
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createImageSendMessage(
      targetId: targetId,
      filePath: filePath,
      width: width,
      height: height,
      thumbnailLocalPath: thumbnailLocalPath,
    );
    try {
      return await EMClient.getInstance.chatManager.sendMessage(msg);
    } catch (err) {
      debugPrint("==IM==:IM发送图片消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<EMMessage?> sendVideoMessage({
    required String targetId,
    required String filePath,
    double? width,
    double? height,
    String? thumbnailLocalPath,
    int duration = 0,
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createVideoSendMessage(
      targetId: targetId,
      filePath: filePath,
      width: width,
      height: height,
      duration: duration,
      displayName: '.mp4',
      thumbnailLocalPath: thumbnailLocalPath,
    );
    try {
      return await EMClient.getInstance.chatManager.sendMessage(msg);
    } catch (err) {
      debugPrint("==IM==:IM发送图片消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<EMMessage?> sendVoiceMessage({
    required String targetId,
    required String filePath,
    int duration = 0,
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createVoiceSendMessage(
      targetId: targetId,
      filePath: filePath,
      duration: duration,
    );
    try {
      return await EMClient.getInstance.chatManager.sendMessage(msg);
    } catch (err) {
      debugPrint("==IM==:IM发送图片消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<EMMessage?> sendGiftMessage({
    required String targetId,
    required String imageUrl,
    String objUrl = '',
    int count = 1,
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createCustomSendMessage(
      targetId: targetId,
      event: CustomMessageType.gift.value,
      params: {
        'type': CustomMessageType.gift.value,
        'imageUrl': imageUrl,
        'objUrl': objUrl,
        'count': count.toString(),
      },
    );
    try {
      return await EMClient.getInstance.chatManager.sendMessage(msg);
    } catch (err) {
      debugPrint("==IM==:IM发送礼物消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<EMMessage?> sendShareMessage({
    required String targetId,
    required String id, // 业务id
    required int type, // 动态类型
    required String image, // 图片
    required String title, // 标题
    required String avatar, // 头像
    required String nickname, // 昵称
    VoidCallback? onError,
  }) async {
    final msg = EMMessage.createCustomSendMessage(
      targetId: targetId,
      event: CustomMessageType.share.value,
      params: {
        'id': id,
        'type': type.toString(),
        'image': image,
        'title': title,
        'avatar': avatar,
        'nickname': nickname,
      },
    );
    try {
      final result = await EMClient.getInstance.chatManager.sendMessage(msg);
      _conversationStreamController.add(null);
      return result;
    } catch (err) {
      debugPrint("==IM==:IM发送礼物消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<EMMessage?> sendCallMessage({
    required String targetId,
    required String event,
    String channelId = '',
    String? from,
    String? to,
    VoidCallback? onError,
  }) async {
    var msg;
    if (event == CustomMessageType.receiveUP.value ||
        event == CustomMessageType.callUP.value) {
      msg = EMMessage.createCmdSendMessage(
        targetId: targetId,
        action: jsonEncode({
          'event': event,
          'channelId': channelId,
          'from': from ?? '',
          'to': to ?? '',
        }),
      );
    } else {
      msg = EMMessage.createCustomSendMessage(
        targetId: targetId,
        event: event,
        params: {
          'channelId': channelId,
          'from': from ?? '',
          'to': to ?? '',
        },
      );
    }
    try {
      return await EMClient.getInstance.chatManager.sendMessage(msg);
    } catch (err) {
      debugPrint("==IM==:IM发送礼物消息失败, err: $err");
      onError?.call();
      return null;
    }
  }

  Future<bool> recallMessage(String? messageId, {VoidCallback? onError}) async {
    if (messageId == null) return false;
    try {
      await EMClient.getInstance.chatManager.recallMessage(messageId);
      return true;
    } catch (err) {
      debugPrint("==IM==:IM撤回消息失败, err: $err");
      onError?.call();
      return false;
    }
  }

  Future<bool> deleteMessage({
    required String conversationId,
    required String messageId,
    VoidCallback? onError,
  }) async {
    try {
      final conversation =
          await EMClient.getInstance.chatManager.getConversation(
        conversationId,
      );
      if (conversation == null) return false;
      await conversation.deleteMessage(messageId);
      return true;
    } catch (err) {
      debugPrint("==IM==:IM删除消息失败, err: $err");
      onError?.call();
      return false;
    }
  }

  // 获取历史消息(服务器)
  Future<List<EMMessage>> loadHistoryMessage(String conversationId) async {
    if (!await isLogin()) return [];
    final chat.CursorResult<chat.Message> cursorResult =
        await EMClient.getInstance.chatManager.fetchHistoryMessagesByOption(
      conversationId,
      chat.ConversationType.Chat,
    );
    return cursorResult.data;
  }

  // 获取历史消息(本地)
  Future<List<EMMessage>> loadLocalHistoryMessage(
    String conversationId, {
    String? startMsgId,
    int limit = 20,
  }) async {
    if (!logined) return [];
    final conversation = await EMClient.getInstance.chatManager.getConversation(
      conversationId,
    );
    if (conversation == null) return [];
    return await conversation.loadMessages(
      startMsgId: startMsgId ?? '',
      loadCount: limit,
    );
  }

  // ============================== conversion =========================================

  // 获取本地所有会话
  Future<List<EMConversation>> loadAllConversations() async {
    if (!isInitialized) {
      debugPrint(
          "==IM==:IM获取本地会话时SDK${isInitialized ? '已初始化' : '未初始化'}, 登录状态:${logined ? '已登录' : '未登录'}");
      return [];
    }
    final conversationList =
        await EMClient.getInstance.chatManager.loadAllConversations();
    debugPrint("==IM==:IM获取本地会话成功 本地会话条数:${conversationList.length}");
    return conversationList;
  }

  // 从服务器拉取会话列表
  // 建议在app安装时或本地没有会话时调用该方法，否则调用 loadAllConversations 获取本地会话即可。
  Future<List<EMConversation>> fetchConversations({int pageSize = 20}) async {
    if (!isInitialized || !logined) {
      debugPrint(
        "==IM==:IM获取服务器会话时SDK${isInitialized ? '已初始化' : '未初始化'}, 登录状态:${logined ? '已登录' : '未登录'}",
      );
      return [];
    }
    try {
      chat.CursorResult<chat.Conversation> cursorResult =
          await EMClient.getInstance.chatManager.fetchConversationsByOptions(
        options: ConversationFetchOptions(pageSize: pageSize),
      );
      return cursorResult.data;
    } catch (e) {
      if (e.toString().contains('user channel service is unopened')) {
        debugPrint("==IM==:IM拉取服务器会话列表失败, 原因:服务未开通");
      }
      debugPrint("==IM==:IM拉取服务器会话列表失败, e: $e");
      return [];
    }
  }

  // 删除会话
  Future<bool> deleteConversation(
    String? conversationId, {
    bool deleteMessages = true,
  }) async {
    if (conversationId == null) return false;
    final result = await EMClient.getInstance.chatManager.deleteConversation(
      conversationId,
      deleteMessages: deleteMessages,
    );
    debugPrint("==IM==:IM本地会话删除结果:$result");
    await EMClient.getInstance.chatManager.deleteRemoteConversation(
      conversationId,
      isDeleteMessage: deleteMessages,
    );
    debugPrint("==IM==:IM远程会话删除成功");
    return result;
  }

  // 清除未读
  Future<void> clearUnread(String? conversationId) async {
    if (conversationId == null) return;
    final conversation = await EMClient.getInstance.chatManager.getConversation(
      conversationId,
    );
    if (conversation == null) return;
    await conversation.markAllMessagesAsRead();
  }

  // ============================== listener =========================================
  void _addChatListener() {
    EMClient.getInstance.chatManager.addEventHandler(
      "receive_message_listener",
      EMChatEventHandler(
        onMessagesReceived: (messages) {
          _messageStreamController.add(messages);
          for (var msg in messages) {
            switch (msg.body.type) {
              case MessageType.TXT:
                EMTextMessageBody body = msg.body as EMTextMessageBody;
                debugPrint("==IM==:收到文本消息: ${body.content}, from: ${msg.from}");
                break;
              case MessageType.IMAGE:
                debugPrint("==IM==:收到图片消息, from: ${msg.from}");
                break;
              case MessageType.VIDEO:
                debugPrint("==IM==:收到视频消息, from: ${msg.from}");
                break;
              case MessageType.VOICE:
                debugPrint("==IM==:收到语音消息, from: ${msg.from}");
                break;
              case MessageType.FILE:
                debugPrint("==IM==:收到文件消息, from: ${msg.from}");
                break;
              case MessageType.CUSTOM:
                final customBody = msg.body as EMCustomMessageBody;
                final event = customBody.event;
                final params = customBody.params;
                final serverTime = msg.serverTime;
                final now = DateTime.now().millisecondsSinceEpoch;
                if ((now - serverTime) > 30000) {
                  debugPrint("==IM==:收到消息, 时间差超过30秒, 不处理");
                  return;
                }
                if (event == CustomMessageType.call.value && params != null) {
                  final channelId = params['channelId'];
                  final from = params['from'];
                  final page = CallPage(
                    type: CallType.receive,
                    channelId: channelId,
                    from: from,
                  );
                  Get.to(() => page);
                }
                debugPrint("==IM==:收到自定义消息($event), from: ${msg.from}");
                break;
              case MessageType.CMD:
                debugPrint("==IM==:收到命令消息, from: ${msg.from}");
                break;
              case MessageType.LOCATION:
                debugPrint("==IM==:收到位置消息, from: ${msg.from}");
                break;
              case chat.MessageType.COMBINE:
                debugPrint("==IM==:收到合并消息, from: ${msg.from}");
                break;
            }
          }
        },
        onConversationsUpdate: () {
          debugPrint("==IM==:会话变动, onConversationsUpdate");
          _conversationStreamController.add(null);
        },
      ),
    );
  }

  // ============================== static tools =========================================
  static String? resolveMessage(EMMessage? msg) {
    if (msg == null) return null;
    switch (msg.body.type) {
      case MessageType.TXT:
        EMTextMessageBody body = msg.body as EMTextMessageBody;
        return body.content;
      case MessageType.IMAGE:
        return '[${T.current.c_image_msg}]';
      case MessageType.VIDEO:
        return '[${T.current.c_video_msg}]';
      case MessageType.VOICE:
        return '[${T.current.c_voice_msg}]';
      case MessageType.CUSTOM:
        final body = msg.body as EMCustomMessageBody;
        if (body.event == 'gift') return '[${T.current.c_gif_msg}]';
        if (body.event == CustomMessageType.call.value) {
          return '[${T.current.c_voice_call}]';
        }
        if (body.event == CustomMessageType.callUP.value) {
          return '[${T.current.c_voice_call}]';
        }
        if (body.event == CustomMessageType.receiveUP.value) {
          return '[${T.current.c_voice_call}]';
        }
        if (body.event == CustomMessageType.share.value) {
          return '[${T.current.c_share_msg}]';
        }
        break;
      case MessageType.FILE:
        debugPrint("==IM==:收到文件消息, from: ${msg.from}");
        break;
      case MessageType.CMD:
        break;
      case MessageType.LOCATION:
        break;
      case chat.MessageType.COMBINE:
        break;
    }
    return null;
  }

  static void jumpChat(String imId) {
    final conversation = EMConversation.fromJson({
      'convId': imId,
      'type': 0,
    });
    Get.to(() => ChatPage(conversation: conversation));
  }

  static void jumpToCustomer() {
    final conversation = EMConversation.fromJson({
      'convId': ImManager.customerId,
      'type': 0,
    });
    final user = chat.UserInfo.fromJson({
      'userId': ImManager.customerId,
      'nickName': 'custom_service',
    });
    Get.to(() => ChatPage(conversation: conversation, user: user));
  }

  // 释放资源
  void removeListener() {
    EMClient.getInstance.chatManager.removeMessageEvent(
      "send_message_change_listener",
    );
    EMClient.getInstance.chatManager.removeEventHandler(
      "receive_message_listener",
    );
    _messageStreamController.close();
  }
}
